What is Circos?

Examples of features you could include

http://circos.ca/intro/features/


Download and Installation

Requirements

  • Perl
    • If you’re in a Unix or MacOS environment then you’ve got it
    • For Windows users see here
  • Perl modules (you’ll certianly need to install a few)
  • True type fonts (TTF), you’ll likely need to recompile the GD graphics library with TTF

How to install and check your installation

  • Download and unpack the Circos tarball
    • You can also download some extra tools and the tutorials, which can be helpful
  • Unpack the tarball: tar xvfz circos-0.69-9.tgz
  • Navigate to Circos directory and check which modules you need
cd ~/Applications/circos-0.69-9/bin
./circos -modules
ok       1.29 Carp
ok       0.36 Clone
ok       2.63 Config::General
ok       3.40 Cwd
ok      2.145 Data::Dumper
ok       2.52 Digest::MD5
ok       2.84 File::Basename
ok       3.40 File::Spec::Functions
ok       0.23 File::Temp
ok       1.51 FindBin
ok       0.39 Font::TTF::Font
ok       2.71 GD
ok        0.2 GD::Polyline
ok       2.39 Getopt::Long
ok       1.16 IO::File
ok       0.33 List::MoreUtils
ok       1.38 List::Util
ok       0.01 Math::Bezier
ok      1.998 Math::BigFloat
ok       0.06 Math::Round
ok       0.08 Math::VecStat
ok       1.03 Memoize
ok       1.32 POSIX
ok       1.08 Params::Validate
ok       1.61 Pod::Usage
ok       2.05 Readonly
ok 2013031301 Regexp::Common
ok       2.84 SVG
ok       1.19 Set::IntSpan
ok     1.6611 Statistics::Basic
ok       2.41 Storable
ok       1.17 Sys::Hostname
ok       2.02 Text::Balanced
ok       0.61 Text::Format
ok     1.9725 Time::HiRes

Installing missing perl modules

See here for more info.

# use the perl CPAN shell
perl -MCPAN -e shell

## within the CPAN shell ##

# do for each module
install Config::General

Compiling GD

By far the most annoying part of the installation… but at least there is a decent tutorial on compiling GD with all relevant libraries here.

Check that everything works

cd ~/Applications/circos-0.69-9/example # or wherever you installed it
./run # will generate a logfile in /example/run.out

If everything looks good, you should see circos.svg and circos.png in circos-0.69-9/example, which appears at the top of this presentation.


Project organization and implementation

# sample directory structure
tree ./circos_data
./circos_data
├── circos.png
├── circos.svg
├── data
│   ├── links.txt
│   ├── segments.txt
│   └── structure.label.txt
└── etc
    ├── bands.conf
    ├── circos.conf
    ├── color.brain.conf
    ├── heatmap.conf
    ├── ideogram.conf
    ├── ideogram.label.conf
    ├── ideogram.position.conf
    ├── segment.order.conf
    ├── text.rules.conf
    └── ticks.conf

2 directories, 15 files
# run circos
cd ./circos_data
circos
debuggroup summary 0.10s welcome to circos v0.69-8 15 Jun 2019 on Perl 5.018004
debuggroup summary 0.10s current working directory /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data
debuggroup summary 0.10s command /Users/dmoracze/Applications/circos-0.69-9/bin/circos [no flags]
debuggroup summary 0.10s guessing configuration file
debuggroup summary 0.10s found conf file /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data/etc/circos.conf
debuggroup summary 0.22s debug will appear for these features: output,summary
debuggroup summary 0.22s bitmap output image ./circos.png
debuggroup summary 0.22s SVG output image ./circos.svg
debuggroup summary 0.22s parsing karyotype and organizing ideograms
debuggroup summary 0.23s karyotype has 16 chromosomes of total size 12,800
debuggroup summary 0.24s applying global and local scaling
debuggroup summary 0.24s allocating image, colors and brushes
debuggroup summary 1.63s drawing 16 ideograms of total size 12,800
debuggroup summary 1.63s drawing highlights and ideograms
debuggroup summary 1.70s found conf file /Users/dmoracze/Applications/circos-0.69-9/bin/../etc/tracks/link.conf
debuggroup summary 1.71s found conf file /Users/dmoracze/Applications/circos-0.69-9/bin/../etc/tracks/link.conf
debuggroup summary 1.71s process track_0 link /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data/data/links.txt
debuggroup summary 1.80s process track_1 link /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data/data/links.txt
debuggroup summary 1.86s drawing link track_0 z 0
debuggroup summary 1.99s drawing link track_1 z 0
debuggroup summary 2.02s found conf file /Users/dmoracze/Applications/circos-0.69-9/bin/../etc/tracks/text.conf
debuggroup summary 2.02s processing track_0 text /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data/data/structure.label.txt
debuggroup summary 2.05s drawing track_0 text z 0 structure.label.txt 
debuggroup summary 2.05s placing text track data/structure.label.txt
debuggroup summary 2.05s ... see progress with -debug_group text
debuggroup summary 2.05s ... see placement summary with -debug_group textplace
debuggroup summary 2.16s found conf file /Users/dmoracze/Applications/circos-0.69-9/bin/../etc/tracks/axis.conf
debuggroup output 2.27s generating output
debuggroup output 2.62s created PNG image ./circos.png (1153 kb)
debuggroup output 2.62s created SVG image ./circos.svg (154 kb)

NB: if you run the circos command without flags, it will look in “logical” places for etc and data, however you can also manually provide the config file using -config filename.conf flag. By default it will write circos.png and circos.svg images to the directory from which the command was run, but this can also be changed using -outputdir and -outputfile flags.


Pros and Cons

Pros

  • Aesthetically appealing (the Ohh factor)
  • Has the ability to present complex multidimensional node- and link-wise metrics (the Ahh factor)
  • Incredibly customizable
  • Text-based data and configuration files make it easily script-able
    • Especially helpful for large datasets

Cons

  • Not simple to install
  • Plots can easily get messy and it takes a lot of thought to figure out how to present your “take home” message
  • Written for genomics, which makes the terminology unintuitive
  • Having complete control can be paralyzing

For example:

My first Circos image (circa 2014)…

Playing with ribbon geometry (circa 2016)…


Typical Circos workflow

From website:

Example

Connectogram recipe tutorial

# get things ready
#setwd('~/iCloud/circos_demo')
library(Hmisc) # for rcorr
library(ggplot2)
library(plyr)
ids <- read.table('./raw/txt/subj_ids.txt', header=TRUE, colClasses="factor") # subject IDs
idx <- read.csv('./raw/txt/reordered_abide_rois_SURF.csv') # indicies to reorder ROIs
ci <- read.csv('./raw/txt/yeo_vol_com.csv') # node communities
pheno <- read.csv('./raw/txt/NYU_pheno.csv') # phenotypic data
pheno$Mean <- as.numeric(pheno$Mean)
pheno$FIQ <- as.numeric(pheno$FIQ)
pheno$AGE_AT_SCAN <- as.numeric(pheno$AGE_AT_SCAN)
pheno$SUB_ID <- as.factor(as.numeric(as.character(pheno$SUB_ID)))

See the raw data

ss <- paste0('00',ids$subj[3])
s.dat <- read.table(paste0('./raw/vol/',ss,'.lh.amy.1D'), stringsAsFactors=FALSE)
head(s.dat) # raw data from amygdala ROI
sig <- as.numeric(s.dat[-1,-1])
ggplot(data.frame(sig), aes(1:length(sig),sig)) + 
    geom_line() +
    theme_bw()

Read in data and create correlation matrices

cormats <- list()
for (ss in levels(ids$subj)){
    id <- paste0('00',ss)
    # read in timeseries
    dim <- read.table(paste0('./raw/vol/',id,'.VS.1D'), stringsAsFactors=FALSE)[-1,-1]
    amy.rh <- as.numeric(read.table(paste0('./raw/vol/',id,'.rh.amy.1D'), stringsAsFactors=FALSE)[-1,-1])
    amy.lh <- as.numeric(read.table(paste0('./raw/vol/',id,'.lh.amy.1D'), stringsAsFactors=FALSE)[-1,-1])
    yeo.rh <- read.table(paste0('./raw/yeo/',id,'_rh.yeo17split.1D'), stringsAsFactors=FALSE)[-1,-1]
    yeo.lh <- read.table(paste0('./raw/yeo/',id,'_lh.yeo17split.1D'), stringsAsFactors=FALSE)[-1,-1]
    # # assemble into timeseries matrix
    raw <- cbind(dim,amy.rh,amy.lh,yeo.rh,yeo.lh)
    raw <- matrix(unlist(lapply(raw,as.numeric)), ncol=length(raw), byrow=FALSE)
    nraw <- raw[,idx$new.reind]
    # create correlation matrix
    cormats[[ss]] <- rcorr(raw)$r
    cormats[[ss]] <- round(cormats[[ss]],4)
    diag(cormats[[ss]]) <- 0
    cormats[[ss]][cormats[[ss]]<0] <- 0
}
heatmap(cormats[[1]])


Calculate participation coefficient

See Rubinov & Sporns, 2010 for more info on graph theoretic metrics.

part.coef <- function(w,Ci) {
    n <- nrow(w) # number of rows (and columns as matrix should be symmetrical 
    Ko <- apply(w,1,sum) # grab node-wise degree
    pos.val <- w # copy matrix to mask
    pos.val[pos.val!=0] <- 1 # binary matrix for community mask
    Gc <- pos.val%*%diag(c(Ci)) # create community mask
    Kc2 <- vector('numeric',n) # container for community-wise degree
    for (i in 1:max(Ci)) {
        Kc2 = Kc2+rowSums(w*(Gc==i))^2 # grab community degree
    }
    P <- round(array(1,n)-Kc2/(Ko^2),4) # calculate and round participation coefficient
    return(P)
}

# calculate participation coefficients
part.coefs <- array(0, dim = c(128, length(ids$subj)))
count <- 0
for (ss in levels(ids$subj)) {
    count <- count+1
    part.coefs[,count] <- part.coef(cormats[[ss]], ci$com)
}
part.coefs <- aperm(part.coefs)
part.coefs <- data.frame(part.coefs, SUB_ID=ids$subj)

# grab the final sample and merge data
roi <- 'X108'
tP <- data.frame(SUB_ID=part.coefs$SUB_ID,roi=part.coefs[,roi])
tP <- merge(pheno, tP, by='SUB_ID')
fin <- subset(tP, tP$SEX==1 & tP$Mean<0.1 & tP$AGE_AT_SCAN<19.74)
fin <- fin[complete.cases(fin$roi),]

Now examine the interaction effect between diagnostic group and age on participation coefficient

summary(lm(roi ~ DX_GROUP*AGE_AT_SCAN + Mean + FIQ + EYE_STATUS_AT_SCAN, data=fin))

Call:
lm(formula = roi ~ DX_GROUP * AGE_AT_SCAN + Mean + FIQ + EYE_STATUS_AT_SCAN, 
    data = fin)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.175880 -0.037234  0.009909  0.033255  0.106159 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)           0.9769632  0.0973128  10.039 3.97e-15 ***
DX_GROUP             -0.1245560  0.0479841  -2.596  0.01152 *  
AGE_AT_SCAN          -0.0205007  0.0062527  -3.279  0.00164 ** 
Mean                  0.4397644  0.3328831   1.321  0.19084    
FIQ                  -0.0004834  0.0004217  -1.147  0.25555    
EYE_STATUS_AT_SCAN    0.0277248  0.0176612   1.570  0.12103    
DX_GROUP:AGE_AT_SCAN  0.0123448  0.0036792   3.355  0.00129 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.05256 on 69 degrees of freedom
Multiple R-squared:  0.2378,    Adjusted R-squared:  0.1715 
F-statistic: 3.588 on 6 and 69 DF,  p-value: 0.003745
mod <- lm(roi ~ Mean + FIQ + EYE_STATUS_AT_SCAN, data=fin)
new <- data.frame(res=residuals(mod),grp=fin$DX_GROUP,age=fin$AGE_AT_SCAN)
new$Group <- revalue(as.factor(new$grp), c('1'='ASD', '2'='TD'))

ggplot(new, aes(age,res,color=Group)) + 
    geom_point() + 
    geom_smooth(method='lm',fill='grey80') +
    scale_color_manual(values=c('forestgreen','steelblue')) +
    scale_x_continuous(breaks=c(6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)) +
    scale_y_continuous(breaks=c(-.1,0)) +
    theme_bw() +
    labs(x='Age',y='Residuals') +
    theme(axis.text.x=element_text(size=14),
        axis.text.y=element_text(size=14))


Prepare Circos data files

The karyotpye file

More info here

chr - ID LABEL START END COLOR
band ID LABEL LABEL START END COLOR
  • chr: definition of a chromosome
  • band: band within a chromosome
  • ID: identifer, which can be used in plot labels
  • start and end: denotes the size of the chromosome (eg 0 99)
  • color

Manually created structure file

cat ./raw/txt/cir_prep_str.csv
module,hemi,roi,col.name,com,ind
Subcortical,lh,VSi,Sub.vsi,2,1
Subcortical,lh,VSs,Sub.vss,2,2
Subcortical,lh,DC,Sub.dc,2,3
Subcortical,lh,DCP,Sub.dcp,2,4
Subcortical,lh,DRP,Sub.drp,2,5
Subcortical,lh,VRP,Sub.vrp,2,6
Subcortical,rh,Vsi,Sub.vsi,2,7
Subcortical,rh,VSs,Sub.vss,2,8
Subcortical,rh,DC,Sub.dc,2,9
Subcortical,rh,DCP,Sub.dc,2,10
Subcortical,rh,DRP,Sub.drp,2,11
Subcortical,rh,VRP,Sub.vrp,2,12
Subcortical,rh,Amy,Sub.amy,1,13
Subcortical,lh,Amy,Sub.amy,1,14
Visual,lh,C.Striate,Visc.striate,3,15
Visual,lh,C.ExStr,Visc.exstr,3,16
Visual,lh,P.Striate,Visp.striate,3,17
Visual,lh,P.ExStrInf,Visp.exstrinf,3,18
Visual,lh,P.ExStrSup,Visp.exstrsup,3,19
Visual,rh,C.Striate,Visc.striate,3,20
Visual,rh,C.ExStr,Visc.exstr,3,21
Visual,rh,P.Striate,Visp.striate,3,22
Visual,rh,P.ExStrInf,Visp.exstrinf,3,23
Visual,rh,P.ExStrSup,Visp.exstrsup,3,24
Somatomotor,lh,A.SomMot,Soma.sommot,4,25
Somatomotor,lh,B.Cent,Somb.cent,4,26
Somatomotor,lh,B.S2,Somb.s2,4,27
Somatomotor,lh,B.Ins,Somb.ins,4,28
Somatomotor,lh,B.Aud,Somb.aud,4,29
Somatomotor,rh,A.SomMot,Soma.sommot,4,30
Somatomotor,rh,B.Cent,Somb.cent,4,31
Somatomotor,rh,B.S2,Somb.s2,4,32
Somatomotor,rh,B.Ins,Somb.ins,4,33
Somatomotor,rh,B.Aud,Somb.aud,4,34
Limbic,lh,A.TempPole,Limba.temppole,4,35
Limbic,lh,B.OFC,Limbb.ofc,4,36
Limbic,rh,A.TempPole,Limba.temppole,4,37
Limbic,rh,B.OFC,Limbb.ofc,4,38
Control,lh,A.Temp,Conta.temp,5,39
Control,lh,A.IPS,Conta.ips,5,40
Control,lh,A.PFCd,Conta.pfcd,5,41
Control,lh,A.PFCl,Conta.pfcl,5,42
Control,lh,A.PFClv,Conta.pfclv,5,43
Control,lh,A.Cinga,Conta.cinga,5,44
Control,lh,B.Temp,Contb.temp,5,45
Control,lh,B.IPL,Contb.ipl,5,46
Control,lh,B.PFCd,Contb.pfcd,5,47
Control,lh,B.PFCl,Contb.pfcl,5,48
Control,lh,B.PFClv,Contb.pfclv,5,49
Control,lh,B.PFCmp,Contb.pfcmp,5,50
Control,lh,C.pCun,Contc.pcun,5,51
Control,lh,C.Cingp,Contc.cingp,5,52
Control,rh,A.Temp,Conta.temp,5,53
Control,rh,A.IPS,Conta.ips,5,54
Control,rh,A.PFCd,Conta.pfcd,5,55
Control,rh,A.PFCl,Conta.pfcl,5,56
Control,rh,A.Cinga,Conta.cinga,5,57
Control,rh,B.Temp,Contb.temp,5,58
Control,rh,B.IPL,Contb.ipl,5,59
Control,rh,B.PFCld,Contb.pfcld,5,60
Control,rh,B.PFClv,Contb.pfclv,5,61
Control,rh,B.PFCmp,Contb.pfcmp,5,62
Control,rh,C.pCun,Contc.pcun,5,63
Control,rh,C.Cingp,Contc.cingp,5,64
VentAttn,lh,A.ParOper,Venta.paroper,6,65
VentAttn,lh,A.PrCv,Venta.prcv,6,66
VentAttn,lh,A.Ins,Venta.ins,6,67
VentAttn,lh,A.ParMed,Venta.parmed,6,68
VentAttn,lh,A.FrMed,Venta.frmed,6,69
VentAttn,lh,B.IPL,Ventb.ipl,6,70
VentAttn,lh,B.PFCd,Ventb.pfcd,6,71
VentAttn,lh,B.PFCl,Ventb.pfcl,6,72
VentAttn,lh,B.PFCv,Ventb.pfcv,6,73
VentAttn,lh,B.OFC,Ventb.ofc,6,74
VentAttn,lh,B.PFCmp,Ventb.pfcmp,6,75
VentAttn,rh,A.ParOper,Venta.paroper,6,76
VentAttn,rh,A.PrC,Venta.prc,6,77
VentAttn,rh,A.PrCv,Venta.prcv,6,78
VentAttn,rh,A.Ins,Venta.ins,6,79
VentAttn,rh,A.ParMed,Venta.parmed,6,80
VentAttn,rh,A.FrMed,Venta.frmed,6,81
VentAttn,rh,B.IPL,Ventb.ipl,6,82
VentAttn,rh,B.PFCd,Ventb.pfcd,6,83
VentAttn,rh,B.PFCl,Ventb.pfcl,6,84
VentAttn,rh,B.PFClv,Ventb.pfcv,6,85
VentAttn,rh,B.PFCv,Ventb.pfcv,6,86
VentAttn,rh,B.PFCmp,Ventb.pfcmp,6,87
VentAttn,rh,B.Cinga,Ventb.cinga,6,88
DorsAttn,lh,A.TempOcc,Dorsa.tempocc,7,89
DorsAttn,lh,A.ParOcc,Dorsa.parocc,7,90
DorsAttn,lh,A.SPL,Dorsa.spl,7,91
DorsAttn,lh,B.TempOcc,Dorsb.tempocc,7,92
DorsAttn,lh,B.PostC,Dorsb.postc,7,93
DorsAttn,lh,B.FEF,Dorsb.fef,7,94
DorsAttn,lh,B.PrCv,Dorsb.prcv,7,95
DorsAttn,rh,A.TempOcc,Dorsa.tempocc,7,96
DorsAttn,rh,A.ParOcc,Dorsa.parocc,7,97
DorsAttn,rh,A.SPL,Dorsa.spl,7,98
DorsAttn,rh,B.TempOcc,Dorsb.tempocc,7,99
DorsAttn,rh,B.PostC,Dorsb.postc,7,100
DorsAttn,rh,B.FEF,Dorsb.fef,7,101
DorsAttn,rh,B.PrCv,Dorsb.prcv,7,102
Default,lh,A.TPJ,DMNa.tpj,8,103
Default,lh,A.PFCd,DMNa.pfcd,8,104
Default,lh,A.PCC,DMNa.pcc,8,105
Default,lh,A.PFCm,DMNa.pfcm,8,106
Default,lh,B.Temp,DMNb.temp,8,107
Default,lh,B.TPJ,DMNb.tpj,8,108
Default,lh,B.PFCd,DMNb.pfcd,8,109
Default,lh,B.PFCl,DMNb.pfcl,8,110
Default,lh,B.PFCv,DMNb.pfcv,8,111
Default,lh,C.TPJ,DMNc.tpj,8,112
Default,lh,C.Rsp,DMNc.rsp,8,113
Default,lh,C.PHC,DMNc.phc,8,114
Default,lh,D.TempPar,DMNd.temppar,8,115
Default,rh,A.Temp,DMNa.temp,8,116
Default,rh,A.TPJ,DMNa.tpj,8,117
Default,rh,A.PFCd,DMNa.pfcd,8,118
Default,rh,A.PCC,DMNa.pcc,8,119
Default,rh,A.PFCm,DMNa.pfcm,8,120
Default,rh,B.Temp,DMNb.temp,8,121
Default,rh,B.AntTemp,DMNb.anttemp,8,122
Default,rh,B.PFCd,DMNb.pfcd,8,123
Default,rh,B.PFCv,DMNb.pfcv,8,124
Default,rh,C.TPJ,DMNc.tpj,8,125
Default,rh,C.Rsp,DMNc.rsp,8,126
Default,rh,C.PHC,DMNc.phc,8,127
Default,rh,D.TempPar,DMNd.temppar,8,128

Structure labels

str <- read.csv('./raw/txt/cir_prep_str.csv',stringsAsFactors=FALSE)
str$module <- factor(str$module,levels=c('Subcortical','Visual','Somatomotor','Limbic','Control','VentAttn','DorsAttn','Default'))
n <- length(str$module)
hemi <- as.factor(c('lh','rh'))

chr <- vector('character',n)
init <- vector('numeric',n)
end <- vector('numeric',n)
name <- vector('character',n)
ii <- 0
for (mm in levels(str$module)) {
    l.loc <- 0
    r.loc <- 0
    for (hh in levels(hemi)) {
        temp <- subset(str,str$module==mm & str$hemi==hh)
        for (rr in 1:length(temp$roi)) {
            ii <- ii+1
            if (temp$hemi[rr]=='lh') {
                chr[ii] <- paste0(temp$module[rr],'-l')
                init[ii] <- l.loc
                end[ii] <- l.loc+99
                name[ii] <- temp$roi[rr]
                l.loc <- l.loc+100

            } else {
                chr[ii] <- paste0(temp$module[rr],'-r')
                init[ii] <- r.loc
                end[ii] <- r.loc+99
                name[ii] <- temp$roi[rr]
                r.loc <- r.loc+100
            }
        }
    }
}
str.label <- data.frame(chr,init,end,name)
write.table(str.label,'./circos_data/data/structure.label.txt',col.names=FALSE,row.names=FALSE,quote=FALSE)
cat ./circos_data/data/structure.label.txt
Subcortical-l 0 99 VSi
Subcortical-l 100 199 VSs
Subcortical-l 200 299 DC
Subcortical-l 300 399 DCP
Subcortical-l 400 499 DRP
Subcortical-l 500 599 VRP
Subcortical-l 600 699 Amy
Subcortical-r 0 99 Vsi
Subcortical-r 100 199 VSs
Subcortical-r 200 299 DC
Subcortical-r 300 399 DCP
Subcortical-r 400 499 DRP
Subcortical-r 500 599 VRP
Subcortical-r 600 699 Amy
Visual-l 0 99 C.Striate
Visual-l 100 199 C.ExStr
Visual-l 200 299 P.Striate
Visual-l 300 399 P.ExStrInf
Visual-l 400 499 P.ExStrSup
Visual-r 0 99 C.Striate
Visual-r 100 199 C.ExStr
Visual-r 200 299 P.Striate
Visual-r 300 399 P.ExStrInf
Visual-r 400 499 P.ExStrSup
Somatomotor-l 0 99 A.SomMot
Somatomotor-l 100 199 B.Cent
Somatomotor-l 200 299 B.S2
Somatomotor-l 300 399 B.Ins
Somatomotor-l 400 499 B.Aud
Somatomotor-r 0 99 A.SomMot
Somatomotor-r 100 199 B.Cent
Somatomotor-r 200 299 B.S2
Somatomotor-r 300 399 B.Ins
Somatomotor-r 400 499 B.Aud
Limbic-l 0 99 A.TempPole
Limbic-l 100 199 B.OFC
Limbic-r 0 99 A.TempPole
Limbic-r 100 199 B.OFC
Control-l 0 99 A.Temp
Control-l 100 199 A.IPS
Control-l 200 299 A.PFCd
Control-l 300 399 A.PFCl
Control-l 400 499 A.PFClv
Control-l 500 599 A.Cinga
Control-l 600 699 B.Temp
Control-l 700 799 B.IPL
Control-l 800 899 B.PFCd
Control-l 900 999 B.PFCl
Control-l 1000 1099 B.PFClv
Control-l 1100 1199 B.PFCmp
Control-l 1200 1299 C.pCun
Control-l 1300 1399 C.Cingp
Control-r 0 99 A.Temp
Control-r 100 199 A.IPS
Control-r 200 299 A.PFCd
Control-r 300 399 A.PFCl
Control-r 400 499 A.Cinga
Control-r 500 599 B.Temp
Control-r 600 699 B.IPL
Control-r 700 799 B.PFCld
Control-r 800 899 B.PFClv
Control-r 900 999 B.PFCmp
Control-r 1000 1099 C.pCun
Control-r 1100 1199 C.Cingp
VentAttn-l 0 99 A.ParOper
VentAttn-l 100 199 A.PrCv
VentAttn-l 200 299 A.Ins
VentAttn-l 300 399 A.ParMed
VentAttn-l 400 499 A.FrMed
VentAttn-l 500 599 B.IPL
VentAttn-l 600 699 B.PFCd
VentAttn-l 700 799 B.PFCl
VentAttn-l 800 899 B.PFCv
VentAttn-l 900 999 B.OFC
VentAttn-l 1000 1099 B.PFCmp
VentAttn-r 0 99 A.ParOper
VentAttn-r 100 199 A.PrC
VentAttn-r 200 299 A.PrCv
VentAttn-r 300 399 A.Ins
VentAttn-r 400 499 A.ParMed
VentAttn-r 500 599 A.FrMed
VentAttn-r 600 699 B.IPL
VentAttn-r 700 799 B.PFCd
VentAttn-r 800 899 B.PFCl
VentAttn-r 900 999 B.PFClv
VentAttn-r 1000 1099 B.PFCv
VentAttn-r 1100 1199 B.PFCmp
VentAttn-r 1200 1299 B.Cinga
DorsAttn-l 0 99 A.TempOcc
DorsAttn-l 100 199 A.ParOcc
DorsAttn-l 200 299 A.SPL
DorsAttn-l 300 399 B.TempOcc
DorsAttn-l 400 499 B.PostC
DorsAttn-l 500 599 B.FEF
DorsAttn-l 600 699 B.PrCv
DorsAttn-r 0 99 A.TempOcc
DorsAttn-r 100 199 A.ParOcc
DorsAttn-r 200 299 A.SPL
DorsAttn-r 300 399 B.TempOcc
DorsAttn-r 400 499 B.PostC
DorsAttn-r 500 599 B.FEF
DorsAttn-r 600 699 B.PrCv
Default-l 0 99 A.TPJ
Default-l 100 199 A.PFCd
Default-l 200 299 A.PCC
Default-l 300 399 A.PFCm
Default-l 400 499 B.Temp
Default-l 500 599 B.TPJ
Default-l 600 699 B.PFCd
Default-l 700 799 B.PFCl
Default-l 800 899 B.PFCv
Default-l 900 999 C.TPJ
Default-l 1000 1099 C.Rsp
Default-l 1100 1199 C.PHC
Default-l 1200 1299 D.TempPar
Default-r 0 99 A.Temp
Default-r 100 199 A.TPJ
Default-r 200 299 A.PFCd
Default-r 300 399 A.PCC
Default-r 400 499 A.PFCm
Default-r 500 599 B.Temp
Default-r 600 699 B.AntTemp
Default-r 700 799 B.PFCd
Default-r 800 899 B.PFCv
Default-r 900 999 C.TPJ
Default-r 1000 1099 C.Rsp
Default-r 1100 1199 C.PHC
Default-r 1200 1299 D.TempPar

Segment labels

dat <- str.label
col.1 <- vector('character',n)
col.2 <- vector('character',n)
col.3 <- vector('character',n)
col.4 <- vector('character',n)
col.5 <- vector('numeric',n)
col.6 <- vector('numeric',n)
col.7 <- vector('character',n)

ii <- 0
for (mm in levels(dat$chr)) {
    ii <- ii+1
    temp <- subset(dat, dat$chr==mm)
    col.1[ii] <- 'chr'
    col.2[ii] <- '-'
    col.3[ii] <- as.character(temp$chr[1])
    col.4[ii] <- strsplit(as.character(temp$chr[1]),'-')[[1]][1]
    col.5[ii] <- 0
    col.6[ii] <- max(temp$end)
    col.7[ii] <- 'black'
    sub.str <- subset(str, str$module == strsplit(as.character(temp$chr[1]),'-')[[1]][1])
    for (rr in 1:length(temp$name)) {
        ii <- ii+1
        col.1[ii] <- 'band'
        col.2[ii] <- as.character(temp$chr[rr])
        col.3[ii] <- as.character(temp$name[rr])
        col.4[ii] <- as.character(temp$name[rr])
        col.5[ii] <- temp$init[rr]
        col.6[ii] <- temp$end[rr]
        col.7[ii] <- sub.str$col.name[grep(temp$name[rr],sub.str$roi)[1]] 
    }
}
seg <- data.frame(col.1,col.2,col.3,col.4,col.5,col.6,col.7)
write.table(seg,'./circos_data/data/segments.txt',col.names=FALSE,row.names=FALSE,quote=FALSE)
cat ./circos_data/data/segments.txt
chr - Control-l Control 0 1399 black
band Control-l A.Temp A.Temp 0 99 Conta.temp
band Control-l A.IPS A.IPS 100 199 Conta.ips
band Control-l A.PFCd A.PFCd 200 299 Conta.pfcd
band Control-l A.PFCl A.PFCl 300 399 Conta.pfcl
band Control-l A.PFClv A.PFClv 400 499 Conta.pfclv
band Control-l A.Cinga A.Cinga 500 599 Conta.cinga
band Control-l B.Temp B.Temp 600 699 Contb.temp
band Control-l B.IPL B.IPL 700 799 Contb.ipl
band Control-l B.PFCd B.PFCd 800 899 Contb.pfcd
band Control-l B.PFCl B.PFCl 900 999 Contb.pfcl
band Control-l B.PFClv B.PFClv 1000 1099 Contb.pfclv
band Control-l B.PFCmp B.PFCmp 1100 1199 Contb.pfcmp
band Control-l C.pCun C.pCun 1200 1299 Contc.pcun
band Control-l C.Cingp C.Cingp 1300 1399 Contc.cingp
chr - Control-r Control 0 1199 black
band Control-r A.Temp A.Temp 0 99 Conta.temp
band Control-r A.IPS A.IPS 100 199 Conta.ips
band Control-r A.PFCd A.PFCd 200 299 Conta.pfcd
band Control-r A.PFCl A.PFCl 300 399 Conta.pfcl
band Control-r A.Cinga A.Cinga 400 499 Conta.cinga
band Control-r B.Temp B.Temp 500 599 Contb.temp
band Control-r B.IPL B.IPL 600 699 Contb.ipl
band Control-r B.PFCld B.PFCld 700 799 Contb.pfcld
band Control-r B.PFClv B.PFClv 800 899 Contb.pfclv
band Control-r B.PFCmp B.PFCmp 900 999 Contb.pfcmp
band Control-r C.pCun C.pCun 1000 1099 Contc.pcun
band Control-r C.Cingp C.Cingp 1100 1199 Contc.cingp
chr - Default-l Default 0 1299 black
band Default-l A.TPJ A.TPJ 0 99 DMNa.tpj
band Default-l A.PFCd A.PFCd 100 199 DMNa.pfcd
band Default-l A.PCC A.PCC 200 299 DMNa.pcc
band Default-l A.PFCm A.PFCm 300 399 DMNa.pfcm
band Default-l B.Temp B.Temp 400 499 DMNb.temp
band Default-l B.TPJ B.TPJ 500 599 DMNb.tpj
band Default-l B.PFCd B.PFCd 600 699 DMNb.pfcd
band Default-l B.PFCl B.PFCl 700 799 DMNb.pfcl
band Default-l B.PFCv B.PFCv 800 899 DMNb.pfcv
band Default-l C.TPJ C.TPJ 900 999 DMNc.tpj
band Default-l C.Rsp C.Rsp 1000 1099 DMNc.rsp
band Default-l C.PHC C.PHC 1100 1199 DMNc.phc
band Default-l D.TempPar D.TempPar 1200 1299 DMNd.temppar
chr - Default-r Default 0 1299 black
band Default-r A.Temp A.Temp 0 99 DMNa.temp
band Default-r A.TPJ A.TPJ 100 199 DMNa.tpj
band Default-r A.PFCd A.PFCd 200 299 DMNa.pfcd
band Default-r A.PCC A.PCC 300 399 DMNa.pcc
band Default-r A.PFCm A.PFCm 400 499 DMNa.pfcm
band Default-r B.Temp B.Temp 500 599 DMNb.temp
band Default-r B.AntTemp B.AntTemp 600 699 DMNb.anttemp
band Default-r B.PFCd B.PFCd 700 799 DMNb.pfcd
band Default-r B.PFCv B.PFCv 800 899 DMNb.pfcv
band Default-r C.TPJ C.TPJ 900 999 DMNc.tpj
band Default-r C.Rsp C.Rsp 1000 1099 DMNc.rsp
band Default-r C.PHC C.PHC 1100 1199 DMNc.phc
band Default-r D.TempPar D.TempPar 1200 1299 DMNd.temppar
chr - DorsAttn-l DorsAttn 0 699 black
band DorsAttn-l A.TempOcc A.TempOcc 0 99 Dorsa.tempocc
band DorsAttn-l A.ParOcc A.ParOcc 100 199 Dorsa.parocc
band DorsAttn-l A.SPL A.SPL 200 299 Dorsa.spl
band DorsAttn-l B.TempOcc B.TempOcc 300 399 Dorsb.tempocc
band DorsAttn-l B.PostC B.PostC 400 499 Dorsb.postc
band DorsAttn-l B.FEF B.FEF 500 599 Dorsb.fef
band DorsAttn-l B.PrCv B.PrCv 600 699 Dorsb.prcv
chr - DorsAttn-r DorsAttn 0 699 black
band DorsAttn-r A.TempOcc A.TempOcc 0 99 Dorsa.tempocc
band DorsAttn-r A.ParOcc A.ParOcc 100 199 Dorsa.parocc
band DorsAttn-r A.SPL A.SPL 200 299 Dorsa.spl
band DorsAttn-r B.TempOcc B.TempOcc 300 399 Dorsb.tempocc
band DorsAttn-r B.PostC B.PostC 400 499 Dorsb.postc
band DorsAttn-r B.FEF B.FEF 500 599 Dorsb.fef
band DorsAttn-r B.PrCv B.PrCv 600 699 Dorsb.prcv
chr - Limbic-l Limbic 0 199 black
band Limbic-l A.TempPole A.TempPole 0 99 Limba.temppole
band Limbic-l B.OFC B.OFC 100 199 Limbb.ofc
chr - Limbic-r Limbic 0 199 black
band Limbic-r A.TempPole A.TempPole 0 99 Limba.temppole
band Limbic-r B.OFC B.OFC 100 199 Limbb.ofc
chr - Somatomotor-l Somatomotor 0 499 black
band Somatomotor-l A.SomMot A.SomMot 0 99 Soma.sommot
band Somatomotor-l B.Cent B.Cent 100 199 Somb.cent
band Somatomotor-l B.S2 B.S2 200 299 Somb.s2
band Somatomotor-l B.Ins B.Ins 300 399 Somb.ins
band Somatomotor-l B.Aud B.Aud 400 499 Somb.aud
chr - Somatomotor-r Somatomotor 0 499 black
band Somatomotor-r A.SomMot A.SomMot 0 99 Soma.sommot
band Somatomotor-r B.Cent B.Cent 100 199 Somb.cent
band Somatomotor-r B.S2 B.S2 200 299 Somb.s2
band Somatomotor-r B.Ins B.Ins 300 399 Somb.ins
band Somatomotor-r B.Aud B.Aud 400 499 Somb.aud
chr - Subcortical-l Subcortical 0 699 black
band Subcortical-l VSi VSi 0 99 Sub.vsi
band Subcortical-l VSs VSs 100 199 Sub.vss
band Subcortical-l DC DC 200 299 Sub.dc
band Subcortical-l DCP DCP 300 399 Sub.dcp
band Subcortical-l DRP DRP 400 499 Sub.drp
band Subcortical-l VRP VRP 500 599 Sub.vrp
band Subcortical-l Amy Amy 600 699 Sub.amy
chr - Subcortical-r Subcortical 0 699 black
band Subcortical-r Vsi Vsi 0 99 Sub.vsi
band Subcortical-r VSs VSs 100 199 Sub.vss
band Subcortical-r DC DC 200 299 Sub.dc
band Subcortical-r DCP DCP 300 399 Sub.dcp
band Subcortical-r DRP DRP 400 499 Sub.drp
band Subcortical-r VRP VRP 500 599 Sub.vrp
band Subcortical-r Amy Amy 600 699 Sub.amy
chr - VentAttn-l VentAttn 0 1099 black
band VentAttn-l A.ParOper A.ParOper 0 99 Venta.paroper
band VentAttn-l A.PrCv A.PrCv 100 199 Venta.prcv
band VentAttn-l A.Ins A.Ins 200 299 Venta.ins
band VentAttn-l A.ParMed A.ParMed 300 399 Venta.parmed
band VentAttn-l A.FrMed A.FrMed 400 499 Venta.frmed
band VentAttn-l B.IPL B.IPL 500 599 Ventb.ipl
band VentAttn-l B.PFCd B.PFCd 600 699 Ventb.pfcd
band VentAttn-l B.PFCl B.PFCl 700 799 Ventb.pfcl
band VentAttn-l B.PFCv B.PFCv 800 899 Ventb.pfcv
band VentAttn-l B.OFC B.OFC 900 999 Ventb.ofc
band VentAttn-l B.PFCmp B.PFCmp 1000 1099 Ventb.pfcmp
chr - VentAttn-r VentAttn 0 1299 black
band VentAttn-r A.ParOper A.ParOper 0 99 Venta.paroper
band VentAttn-r A.PrC A.PrC 100 199 Venta.prcv
band VentAttn-r A.PrCv A.PrCv 200 299 Venta.prcv
band VentAttn-r A.Ins A.Ins 300 399 Venta.ins
band VentAttn-r A.ParMed A.ParMed 400 499 Venta.parmed
band VentAttn-r A.FrMed A.FrMed 500 599 Venta.frmed
band VentAttn-r B.IPL B.IPL 600 699 Ventb.ipl
band VentAttn-r B.PFCd B.PFCd 700 799 Ventb.pfcd
band VentAttn-r B.PFCl B.PFCl 800 899 Ventb.pfcl
band VentAttn-r B.PFClv B.PFClv 900 999 Ventb.pfcv
band VentAttn-r B.PFCv B.PFCv 1000 1099 Ventb.pfcv
band VentAttn-r B.PFCmp B.PFCmp 1100 1199 Ventb.pfcmp
band VentAttn-r B.Cinga B.Cinga 1200 1299 Ventb.cinga
chr - Visual-l Visual 0 499 black
band Visual-l C.Striate C.Striate 0 99 Visc.striate
band Visual-l C.ExStr C.ExStr 100 199 Visc.exstr
band Visual-l P.Striate P.Striate 200 299 Visp.striate
band Visual-l P.ExStrInf P.ExStrInf 300 399 Visp.exstrinf
band Visual-l P.ExStrSup P.ExStrSup 400 499 Visp.exstrsup
chr - Visual-r Visual 0 499 black
band Visual-r C.Striate C.Striate 0 99 Visc.striate
band Visual-r C.ExStr C.ExStr 100 199 Visc.exstr
band Visual-r P.Striate P.Striate 200 299 Visp.striate
band Visual-r P.ExStrInf P.ExStrInf 300 399 Visp.exstrinf
band Visual-r P.ExStrSup P.ExStrSup 400 499 Visp.exstrsup

Circos config file

cat ./circos_data/etc/circos.conf
<<include ideogram.conf>>

chromosomes_units = 100

<<include ticks.conf>>

<image>
    angle_offset* = 90.75
    <<include etc/image.conf>>
</image>

karyotype = data/segments.txt

<<include segment.order.conf>>

chromosomes_reverse = /.*-l/

#hm_colors = purd-4-seq

<plots>
    #<<include heatmap.conf>>

    <plot>
        type       = text
        file       = data/structure.label.txt
        color      = black
        label_font = default
        label_size = 26
        r0         = 1.02r
        r1         = 1.2r
        rpadding   = 0p

        <rules>
            <rule>
                condition = var(value) eq "B.TPJ"
                label_font = bold
                label_size = 32
            </rule>
        </rules>
    </plot>
</plots>

<links>
    <link>
        file                = data/links.txt
        radius              = .99r
        bezier_radius       = 0r
        bezier_radius_purity    = .65
        crest               = 0.5
        ribbon          = yes
        flat            = yes
        show            = yes
        <rules>
            <rule>
                condition   = 1
                z       = eval(remap_int(var(score),0,.2,1,400))
                flow        = continue
            </rule>

            <rule>
                condition   = var(score) < 0.025
                show        = no
            </rule>

            <rule>
                condition   = between(Default-l,Default-r)
                color       = 235,91,110,0.45
                crest       = .4
                flow        = continue
            </rule>

            <rule>
                condition   = var(intrachr)
                color       = 235,91,110,0.3
                crest       = .4
                flow        = continue
            </rule>

            <rule>
                condition   = on(VentAttn-l) || on(VentAttn-r)
                color       = 225,83,255,0.45
                flow        = continue
            </rule>

            <rule>
                condition   = on(DorsAttn-l) || on(DorsAttn-r)
                color       = 32,147,50,0.45
                crest       = .5
                flow        = continue
            </rule>

            <rule>
                condition   = on(Control-l) || on(Control-r)
                color       = 248,163,71,0.45
                flow        = continue
            </rule>

            <rule>
                condition   = on(Limbic-l) || on(Limbic-r)
                color       = 195,205,130,0.45
                flow        = continue
            </rule>

            <rule>
                condition   = on(Somatomotor-l) || on(Somatomotor-r)
                color       = 96,141,195,0.45
                flow        = continue
            </rule>

            <rule>
                condition   = on(Visual-l) || on(Visual-r)
                color       = 153,51,159,0.45
                flow        = continue
            </rule>

            <rule>
                condition   = on(Subcortical-l) || on(Subcortical-r)
                color       = 130,130,130,.45
                flow        = continue
            </rule>
        </rules>
    </link>

    <link>
        file                = data/links.txt
        radius              = .99r
        bezier_radius       = 0r
        bezier_radius_purity    = .65
        crest               = 0.5
        color           = black
        show            = yes
        <rules>
            <rule>
                condition   = 1
                z       = eval(remap_int(var(score),0,.2,1,400))
                flow        = continue
            </rule>

            <rule>
                condition   = var(score) < 0.025
                show        = no
            </rule>

            <rule>
                condition   = between(Default-l,Default-r)
                crest       = .4
                flow        = continue
            </rule>

            <rule>
                condition   = var(intrachr)
                crest       = .4
                flow        = continue
            </rule>

            <rule>
                condition   = var(score) > 0.025 && var(score) < 0.05
                show        = yes
                color       = grey
                thickness   = 1
            </rule>

            <rule>
                condition   = var(score) > 0.05 && var(score) < 0.075
                show        = yes
                thickness   = 1
            </rule>

            <rule>
                condition   = var(score) > 0.075 && var(score) < 0.1
                show        = yes
                thickness   = 2
            </rule>

            <rule>
                condition   = var(score) > 0.1 && var(score) < 0.125
                show        = yes
                thickness   = 3
            </rule>

            <rule>
                condition   = var(score) > 0.125 && var(score) < 0.15
                show        = yes
                thickness   = 4
            </rule>

            <rule>
                condition   = var(score) > 0.15
                show        = yes
                thickness   = 5
            </rule>
        </rules>
    </link>
</links>

<<include etc/colors_fonts_patterns.conf>>

<colors>
    <<include color.brain.conf>>
</colors>

restrict_parameter_names* = no

<<include etc/housekeeping.conf>>

Sample imported config file

cat ./circos_data/etc/ideogram.conf
<ideogram>
    <spacing>
        default = 0.005r
    </spacing>

    <<include ideogram.position.conf>>
    <<include ideogram.label.conf>>
    <<include bands.conf>>
</ideogram>

Run Circos

cd ./circos_data
circos
debuggroup summary 0.09s welcome to circos v0.69-8 15 Jun 2019 on Perl 5.018004
debuggroup summary 0.10s current working directory /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data
debuggroup summary 0.10s command /Users/dmoracze/Applications/circos-0.69-9/bin/circos [no flags]
debuggroup summary 0.10s guessing configuration file
debuggroup summary 0.10s found conf file /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data/etc/circos.conf
debuggroup summary 0.22s debug will appear for these features: output,summary
debuggroup summary 0.22s bitmap output image ./circos.png
debuggroup summary 0.22s SVG output image ./circos.svg
debuggroup summary 0.22s parsing karyotype and organizing ideograms
debuggroup summary 0.23s karyotype has 16 chromosomes of total size 12,800
debuggroup summary 0.23s applying global and local scaling
debuggroup summary 0.24s allocating image, colors and brushes
debuggroup summary 1.61s drawing 16 ideograms of total size 12,800
debuggroup summary 1.61s drawing highlights and ideograms
debuggroup summary 1.69s found conf file /Users/dmoracze/Applications/circos-0.69-9/bin/../etc/tracks/link.conf
debuggroup summary 1.69s found conf file /Users/dmoracze/Applications/circos-0.69-9/bin/../etc/tracks/link.conf
debuggroup summary 1.69s process track_0 link /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data/data/links.txt
debuggroup summary 1.79s process track_1 link /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data/data/links.txt
debuggroup summary 1.84s drawing link track_0 z 0
debuggroup summary 1.97s drawing link track_1 z 0
debuggroup summary 2.00s found conf file /Users/dmoracze/Applications/circos-0.69-9/bin/../etc/tracks/text.conf
debuggroup summary 2.00s processing track_0 text /Users/dmoracze/Desktop/coders_forum/2019_10/circos_data/data/structure.label.txt
debuggroup summary 2.03s drawing track_0 text z 0 structure.label.txt 
debuggroup summary 2.03s placing text track data/structure.label.txt
debuggroup summary 2.03s ... see progress with -debug_group text
debuggroup summary 2.03s ... see placement summary with -debug_group textplace
debuggroup summary 2.14s found conf file /Users/dmoracze/Applications/circos-0.69-9/bin/../etc/tracks/axis.conf
debuggroup output 2.23s generating output
debuggroup output 2.56s created PNG image ./circos.png (1153 kb)
debuggroup output 2.56s created SVG image ./circos.svg (154 kb)

Final plot

Circos does not generate legends or extra labels (such as the hemisphere designation in my figure). These need to be manually added in your figure editor (e.g., Illustration, Power Point)

LS0tCnRpdGxlOiAiQ3JlYXRpbmcgY29ubmVjdG9ncmFtcyB1c2luZyBDaXJjb3MiCmF1dGhvcjogIkR1c3RpbiBNb3JhY3pld3NraSIKZGF0ZTogIjEwLzMvMjAxOSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQo8Y2VudGVyPgoJIVtdKC4vaW1nL3NhbXBsZS5wbmcpe3dpZHRoPTEwMCV9CjwvY2VudGVyPgoKLS0tLS0KCiMjIFdoYXQgaXMgQ2lyY29zPwoKLSBBIHBlcmwtYmFzZWQgc29mdHdhcmUgcGFja2FnZSBmb3IgdmlzdWFsaXppbmcgZGF0YSBpbiBhIGNpcmN1bHVhciBmb3JtYXQKLSBGcm9tIFtodHRwOi8vY2lyY29zLmNhXShodHRwOi8vY2lyY29zLmNhLyk6IF8iLi4uIGEgaGlnaCBkYXRhLXRvLWluayByYXRpbywgcmljaGx5IGxheWVyZWQgZGF0YSBhbmQgcGxlYXNhbnQgc3ltbWV0cmllcyJfCi0gXyJDaXJjb3MgYXR0ZW1wdHMgdG8gYnJpbmcgYSBkaWZmZXJlbnQgYWVzdGhldGljIHRvIHNjaWVuY2UgYW5kIHN0cmlrZSBhIGJhbGFuY2UgZmxleGliaWxpdHkgYW5kIGVhc2Utb2YtdXNlIl8KLSBJbWFnZXMgYXJlIGRlZmluZWQgdXNpbmcgdGV4dC1iYXNlZCBjb25maWd1cmF0aW9uIGFuZCBkYXRhIGZpbGVzLCB3aGljaCBtYWtlcyBpdCBlYXNpbHkgc2NyaXB0LWFibGUKLSBUaGUgd2Vic2l0ZSBpcyBzdXBlciBpbmZvcm1hdGl2ZSwgaWYgbm90IGEgYml0IG92ZXJ3aGVsbWluZyAoc28gbWFueSBmZWF0dXJlcykuIAotIE1hc3NpdmUgYW1vdW50cyBvZiBmZWF0dXJlIHR1dG9yaWFscyBhcmUgYXZhaWxhYmxlIG9uIHRoZSB3ZWJzaXRlIGFuZCB0byBkb3dubG9hZCB0byBydW4vY3VzdG9taXplIG9uIHlvdXIgb3duCgkrIFdhbnQgdG8gcGxheSB3aXRoIGJhbmQgdHJhbnNwYXJhbmN5PwoJKyBXYW50IHRvIGFkZCBhIGJhbmQgb2Ygbm9kZS1zcGVjaWZpYyBoaXN0b2dyYW1zPwoJKyBXYW50IHRvIG9mZnNldCBhIHBhcnRpY2lsYXIgc2VjdGlvbiBvZiB5b3VyIGNvbm5lY3RvZ3JhbSBmb3IgZW1waGFzaXM/CgkrIFNlZSB0aGUgdHV0b3JpYWxzIQoKIyMjIyBFeGFtcGxlcyBvZiBmZWF0dXJlcyB5b3UgY291bGQgaW5jbHVkZQoKW2h0dHA6Ly9jaXJjb3MuY2EvaW50cm8vZmVhdHVyZXMvXShodHRwOi8vY2lyY29zLmNhL2ludHJvL2ZlYXR1cmVzLykKCjxjZW50ZXI+CgkhW10oLi9pbWcvZXhhbXBsZV9wbG90cy5wbmcpe3dpZHRoPTYwJX0KPC9jZW50ZXI+CgotLS0tLQoKCiMjIERvd25sb2FkIGFuZCBJbnN0YWxsYXRpb24KCiMjIyMgUmVxdWlyZW1lbnRzCgotIFBlcmwKCSsgSWYgeW91J3JlIGluIGEgVW5peCBvciBNYWNPUyBlbnZpcm9ubWVudCB0aGVuIHlvdSd2ZSBnb3QgaXQKCSsgRm9yIFdpbmRvd3MgdXNlcnMgc2VlIFtoZXJlXShodHRwOi8vY2lyY29zLmNhL3NvZnR3YXJlL2luc3RhbGxhdGlvbi8pCi0gUGVybCBtb2R1bGVzICh5b3UnbGwgY2VydGlhbmx5IG5lZWQgdG8gaW5zdGFsbCBhIGZldykKLSBUcnVlIHR5cGUgZm9udHMgKFRURiksIHlvdSdsbCBsaWtlbHkgbmVlZCB0byByZWNvbXBpbGUgdGhlIEdEIGdyYXBoaWNzIGxpYnJhcnkgd2l0aCBUVEYKCiMjIyMgSG93IHRvIGluc3RhbGwgYW5kIGNoZWNrIHlvdXIgaW5zdGFsbGF0aW9uCgotIERvd25sb2FkIGFuZCB1bnBhY2sgdGhlIFtDaXJjb3MgdGFyYmFsbF0oaHR0cDovL2NpcmNvcy5jYS9zb2Z0d2FyZS9kb3dubG9hZC8pCgkrIFlvdSBjYW4gYWxzbyBkb3dubG9hZCBzb21lIGV4dHJhIHRvb2xzIGFuZCB0aGUgdHV0b3JpYWxzLCB3aGljaCBjYW4gYmUgaGVscGZ1bAotIFVucGFjayB0aGUgdGFyYmFsbDogYHRhciB4dmZ6IGNpcmNvcy0wLjY5LTkudGd6YAotIE5hdmlnYXRlIHRvIENpcmNvcyBkaXJlY3RvcnkgYW5kIGNoZWNrIHdoaWNoIG1vZHVsZXMgeW91IG5lZWQKCmBgYHtyIGVuZ2luZSA9ICdiYXNoJywgY29tbWVudCA9ICcnfQpjZCB+L0FwcGxpY2F0aW9ucy9jaXJjb3MtMC42OS05L2JpbgouL2NpcmNvcyAtbW9kdWxlcwpgYGAKCiMjIyMgSW5zdGFsbGluZyBtaXNzaW5nIHBlcmwgbW9kdWxlcwoKU2VlIFtoZXJlXShodHRwOi8vY2lyY29zLmNhL2RvY3VtZW50YXRpb24vdHV0b3JpYWxzL2NvbmZpZ3VyYXRpb24vcGVybF9hbmRfbW9kdWxlcykgZm9yIG1vcmUgaW5mby4KCmBgYHtyIGVuZ2luZSA9ICdiYXNoJywgY29tbWVudCA9ICcnLCBldmFsID0gRkFMU0V9CiMgdXNlIHRoZSBwZXJsIENQQU4gc2hlbGwKcGVybCAtTUNQQU4gLWUgc2hlbGwKCiMjIHdpdGhpbiB0aGUgQ1BBTiBzaGVsbCAjIwoKIyBkbyBmb3IgZWFjaCBtb2R1bGUKaW5zdGFsbCBDb25maWc6OkdlbmVyYWwKYGBgCgojIyMjIENvbXBpbGluZyBHRAoKQnkgZmFyIHRoZSBtb3N0IGFubm95aW5nIHBhcnQgb2YgdGhlIGluc3RhbGxhdGlvbi4uLiBidXQgYXQgbGVhc3QgdGhlcmUgaXMgYSBkZWNlbnQgdHV0b3JpYWwgb24gY29tcGlsaW5nIEdEIHdpdGggYWxsIHJlbGV2YW50IGxpYnJhcmllcyBbaGVyZV0oaHR0cDovL2NpcmNvcy5jYS9kb2N1bWVudGF0aW9uL3R1dG9yaWFscy9jb25maWd1cmF0aW9uL3BlcmxfYW5kX21vZHVsZXMpLgoKIyMjIyBDaGVjayB0aGF0IGV2ZXJ5dGhpbmcgd29ya3MKCmBgYHtyIGVuZ2luZSA9ICdiYXNoJywgY29tbWVudCA9ICcnLCBldmFsID0gRkFMU0V9CmNkIH4vQXBwbGljYXRpb25zL2NpcmNvcy0wLjY5LTkvZXhhbXBsZSAjIG9yIHdoZXJldmVyIHlvdSBpbnN0YWxsZWQgaXQKLi9ydW4gIyB3aWxsIGdlbmVyYXRlIGEgbG9nZmlsZSBpbiAvZXhhbXBsZS9ydW4ub3V0CmBgYAoKSWYgZXZlcnl0aGluZyBsb29rcyBnb29kLCB5b3Ugc2hvdWxkIHNlZSBgY2lyY29zLnN2Z2AgYW5kIGBjaXJjb3MucG5nYCBpbiBgY2lyY29zLTAuNjktOS9leGFtcGxlYCwgd2hpY2ggYXBwZWFycyBhdCB0aGUgdG9wIG9mIHRoaXMgcHJlc2VudGF0aW9uLgoKCi0tLS0tCgoKIyMgUHJvamVjdCBvcmdhbml6YXRpb24gYW5kIGltcGxlbWVudGF0aW9uCgpgYGB7ciBlbmdpbmUgPSAnYmFzaCcsIGNvbW1lbnQgPSAnJ30KIyBzYW1wbGUgZGlyZWN0b3J5IHN0cnVjdHVyZQp0cmVlIC4vY2lyY29zX2RhdGEKYGBgCgpgYGB7ciBlbmdpbmUgPSAnYmFzaCcsIGNvbW1lbnQgPSAnJ30KIyBydW4gY2lyY29zCmNkIC4vY2lyY29zX2RhdGEKY2lyY29zCmBgYAoKKipOQjoqKiBpZiB5b3UgcnVuIHRoZSBgY2lyY29zYCBjb21tYW5kIHdpdGhvdXQgZmxhZ3MsIGl0IHdpbGwgbG9vayBpbiAibG9naWNhbCIgcGxhY2VzIGZvciBgZXRjYCBhbmQgYGRhdGFgLCBob3dldmVyIHlvdSBjYW4gYWxzbyBtYW51YWxseSBwcm92aWRlIHRoZSBjb25maWcgZmlsZSB1c2luZyBgLWNvbmZpZyBmaWxlbmFtZS5jb25mYCBmbGFnLiBCeSBkZWZhdWx0IGl0IHdpbGwgd3JpdGUgYGNpcmNvcy5wbmdgIGFuZCBgY2lyY29zLnN2Z2AgaW1hZ2VzIHRvIHRoZSBkaXJlY3RvcnkgZnJvbSB3aGljaCB0aGUgY29tbWFuZCB3YXMgcnVuLCBidXQgdGhpcyBjYW4gYWxzbyBiZSBjaGFuZ2VkIHVzaW5nIGAtb3V0cHV0ZGlyYCBhbmQgYC1vdXRwdXRmaWxlYCBmbGFncy4KCi0tLS0tCgoKIyMgUHJvcyBhbmQgQ29ucwoKIyMjIyBQcm9zCgotIEFlc3RoZXRpY2FsbHkgYXBwZWFsaW5nICh0aGUgT2hoIGZhY3RvcikKLSBIYXMgdGhlIGFiaWxpdHkgdG8gcHJlc2VudCBjb21wbGV4IG11bHRpZGltZW5zaW9uYWwgbm9kZS0gYW5kIGxpbmstd2lzZSBtZXRyaWNzICh0aGUgQWhoIGZhY3RvcikKLSBJbmNyZWRpYmx5IGN1c3RvbWl6YWJsZQotIFRleHQtYmFzZWQgZGF0YSBhbmQgY29uZmlndXJhdGlvbiBmaWxlcyBtYWtlIGl0IGVhc2lseSBzY3JpcHQtYWJsZQoJKyBFc3BlY2lhbGx5IGhlbHBmdWwgZm9yIGxhcmdlIGRhdGFzZXRzCgojIyMjIENvbnMKCi0gTm90IHNpbXBsZSB0byBpbnN0YWxsCi0gUGxvdHMgY2FuIGVhc2lseSBnZXQgbWVzc3kgYW5kIGl0IHRha2VzIGEgbG90IG9mIHRob3VnaHQgdG8gZmlndXJlIG91dCBob3cgdG8gcHJlc2VudCB5b3VyICJ0YWtlIGhvbWUiIG1lc3NhZ2UKLSBXcml0dGVuIGZvciBnZW5vbWljcywgd2hpY2ggbWFrZXMgdGhlIHRlcm1pbm9sb2d5IHVuaW50dWl0aXZlCi0gSGF2aW5nIGNvbXBsZXRlIGNvbnRyb2wgY2FuIGJlIHBhcmFseXppbmcKCkZvciBleGFtcGxlOgoKTXkgZmlyc3QgQ2lyY29zIGltYWdlIChjaXJjYSAyMDE0KS4uLgoKPGNlbnRlcj4KCSFbXSguL2ltZy9hdnNfY2lyY29zLnBuZyl7d2lkdGg9NzUlfQo8L2NlbnRlcj4KClBsYXlpbmcgd2l0aCByaWJib24gZ2VvbWV0cnkgKGNpcmNhIDIwMTYpLi4uCgo8Y2VudGVyPgoJIVtdKC4vaW1nL3JsX2NpcmNvcy5wbmcpe3dpZHRoPTc1JX0KPC9jZW50ZXI+CgotLS0tLQoKIyMgVHlwaWNhbCBDaXJjb3Mgd29ya2Zsb3cKCltGcm9tIHdlYnNpdGU6XShodHRwOi8vd3d3LmNpcmNvcy5jYS9kb2N1bWVudGF0aW9uL3R1dG9yaWFscy9jb25maWd1cmF0aW9uL2NvbmZpZ3VyYXRpb25fZmlsZXMvKQoKLSBEZXRlcm1pbmUgaG93IHlvdSdkIGxpa2UgdG8gdmlzdWFsaXplIHlvdXIgZGF0YQotIFBhcnNlIHRoZSBkYXRhIGludG8gQ2lyY29zIGZvcm1hdAotIENvbnN0cnVjdGlvbmcgYSBjb25maWd1cmF0aW9uIGZpbGUKLSBSdW5uaW5nIENpcmNvcyB0byBnZW5lcmF0ZSBpbWFnZQotIEVkaXQgaW1hZ2UgZm9yIHB1YmxpY2F0aW9uICh0byBzYXksIGFkZCBhIGxlZ2VuZCkKCgojIyMgW1NlZSB0dXRvcmlhbHMgZm9yIG1vcmUgaW5mbyB0aGFuIHlvdSBuZWVkIHRvIGtub3ddKGh0dHA6Ly9jaXJjb3MuY2EvZG9jdW1lbnRhdGlvbi90dXRvcmlhbHMvKQoKCi0tLS0tCgojIyBFeGFtcGxlCgojIyMjIFtDb25uZWN0b2dyYW0gcmVjaXBlIHR1dG9yaWFsXShodHRwOi8vY2lyY29zLmNhL2RvY3VtZW50YXRpb24vdHV0b3JpYWxzL3JlY2lwZXMvY29ydGljYWxfbWFwcy8pCgo8Y2VudGVyPgoJIVtdKC4vY2lyY29zX2RhdGEvY2lyY29zLnBuZyl7d2lkdGg9NzUlfQo8L2NlbnRlcj4KCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CiMgZ2V0IHRoaW5ncyByZWFkeQojc2V0d2QoJ34vaUNsb3VkL2NpcmNvc19kZW1vJykKbGlicmFyeShIbWlzYykgIyBmb3IgcmNvcnIKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBseXIpCmlkcyA8LSByZWFkLnRhYmxlKCcuL3Jhdy90eHQvc3Vial9pZHMudHh0JywgaGVhZGVyPVRSVUUsIGNvbENsYXNzZXM9ImZhY3RvciIpICMgc3ViamVjdCBJRHMKaWR4IDwtIHJlYWQuY3N2KCcuL3Jhdy90eHQvcmVvcmRlcmVkX2FiaWRlX3JvaXNfU1VSRi5jc3YnKSAjIGluZGljaWVzIHRvIHJlb3JkZXIgUk9JcwpjaSA8LSByZWFkLmNzdignLi9yYXcvdHh0L3llb192b2xfY29tLmNzdicpICMgbm9kZSBjb21tdW5pdGllcwpwaGVubyA8LSByZWFkLmNzdignLi9yYXcvdHh0L05ZVV9waGVuby5jc3YnKSAjIHBoZW5vdHlwaWMgZGF0YQpwaGVubyRNZWFuIDwtIGFzLm51bWVyaWMocGhlbm8kTWVhbikKcGhlbm8kRklRIDwtIGFzLm51bWVyaWMocGhlbm8kRklRKQpwaGVubyRBR0VfQVRfU0NBTiA8LSBhcy5udW1lcmljKHBoZW5vJEFHRV9BVF9TQ0FOKQpwaGVubyRTVUJfSUQgPC0gYXMuZmFjdG9yKGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHBoZW5vJFNVQl9JRCkpKQpgYGAKCjxjZW50ZXI+CgkhW10oLi9pbWcvcm9pcy5wbmcpe3dpZHRoPTEwMCV9CjwvY2VudGVyPgoKLS0tLS0KCgojIyMjIFNlZSB0aGUgcmF3IGRhdGEKCmBgYHtyIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA4LCBmaWcuYWxpZ24gPSAnY2VudGVyJ30Kc3MgPC0gcGFzdGUwKCcwMCcsaWRzJHN1YmpbM10pCnMuZGF0IDwtIHJlYWQudGFibGUocGFzdGUwKCcuL3Jhdy92b2wvJyxzcywnLmxoLmFteS4xRCcpLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQpoZWFkKHMuZGF0KSAjIHJhdyBkYXRhIGZyb20gYW15Z2RhbGEgUk9JCnNpZyA8LSBhcy5udW1lcmljKHMuZGF0Wy0xLC0xXSkKZ2dwbG90KGRhdGEuZnJhbWUoc2lnKSwgYWVzKDE6bGVuZ3RoKHNpZyksc2lnKSkgKyAKCWdlb21fbGluZSgpICsKCXRoZW1lX2J3KCkKYGBgCgoKIyMjIFJlYWQgaW4gZGF0YSBhbmQgY3JlYXRlIGNvcnJlbGF0aW9uIG1hdHJpY2VzCgpgYGB7ciBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNiwgZmlnLmFsaWduID0gJ2NlbnRlcid9CmNvcm1hdHMgPC0gbGlzdCgpCmZvciAoc3MgaW4gbGV2ZWxzKGlkcyRzdWJqKSl7CglpZCA8LSBwYXN0ZTAoJzAwJyxzcykKCSMgcmVhZCBpbiB0aW1lc2VyaWVzCglkaW0gPC0gcmVhZC50YWJsZShwYXN0ZTAoJy4vcmF3L3ZvbC8nLGlkLCcuVlMuMUQnKSwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSlbLTEsLTFdCglhbXkucmggPC0gYXMubnVtZXJpYyhyZWFkLnRhYmxlKHBhc3RlMCgnLi9yYXcvdm9sLycsaWQsJy5yaC5hbXkuMUQnKSwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSlbLTEsLTFdKQoJYW15LmxoIDwtIGFzLm51bWVyaWMocmVhZC50YWJsZShwYXN0ZTAoJy4vcmF3L3ZvbC8nLGlkLCcubGguYW15LjFEJyksIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpWy0xLC0xXSkKCXllby5yaCA8LSByZWFkLnRhYmxlKHBhc3RlMCgnLi9yYXcveWVvLycsaWQsJ19yaC55ZW8xN3NwbGl0LjFEJyksIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpWy0xLC0xXQoJeWVvLmxoIDwtIHJlYWQudGFibGUocGFzdGUwKCcuL3Jhdy95ZW8vJyxpZCwnX2xoLnllbzE3c3BsaXQuMUQnKSwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSlbLTEsLTFdCgkjICMgYXNzZW1ibGUgaW50byB0aW1lc2VyaWVzIG1hdHJpeAoJcmF3IDwtIGNiaW5kKGRpbSxhbXkucmgsYW15LmxoLHllby5yaCx5ZW8ubGgpCglyYXcgPC0gbWF0cml4KHVubGlzdChsYXBwbHkocmF3LGFzLm51bWVyaWMpKSwgbmNvbD1sZW5ndGgocmF3KSwgYnlyb3c9RkFMU0UpCglucmF3IDwtIHJhd1ssaWR4JG5ldy5yZWluZF0KCSMgY3JlYXRlIGNvcnJlbGF0aW9uIG1hdHJpeAoJY29ybWF0c1tbc3NdXSA8LSByY29ycihyYXcpJHIKCWNvcm1hdHNbW3NzXV0gPC0gcm91bmQoY29ybWF0c1tbc3NdXSw0KQoJZGlhZyhjb3JtYXRzW1tzc11dKSA8LSAwCgljb3JtYXRzW1tzc11dW2Nvcm1hdHNbW3NzXV08MF0gPC0gMAp9CmhlYXRtYXAoY29ybWF0c1tbMV1dKQpgYGAKCi0tLS0tCgoKIyMjIENhbGN1bGF0ZSBwYXJ0aWNpcGF0aW9uIGNvZWZmaWNpZW50CgpTZWUgW1J1Ymlub3YgJiBTcG9ybnMsIDIwMTBdKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzEwNTM4MTE5MDkwMTA3NFg/dmlhJTNEaWh1YikgZm9yIG1vcmUgaW5mbyBvbiBncmFwaCB0aGVvcmV0aWMgbWV0cmljcy4KCjxjZW50ZXI+CgkhW10oLi9pbWcvcGFydC5wbmcpe3dpZHRoPTEwMCV9CjwvY2VudGVyPgoKYGBge3J9CnBhcnQuY29lZiA8LSBmdW5jdGlvbih3LENpKSB7CgluIDwtIG5yb3codykgIyBudW1iZXIgb2Ygcm93cyAoYW5kIGNvbHVtbnMgYXMgbWF0cml4IHNob3VsZCBiZSBzeW1tZXRyaWNhbCAKCUtvIDwtIGFwcGx5KHcsMSxzdW0pICMgZ3JhYiBub2RlLXdpc2UgZGVncmVlCglwb3MudmFsIDwtIHcgIyBjb3B5IG1hdHJpeCB0byBtYXNrCglwb3MudmFsW3Bvcy52YWwhPTBdIDwtIDEgIyBiaW5hcnkgbWF0cml4IGZvciBjb21tdW5pdHkgbWFzawoJR2MgPC0gcG9zLnZhbCUqJWRpYWcoYyhDaSkpICMgY3JlYXRlIGNvbW11bml0eSBtYXNrCglLYzIgPC0gdmVjdG9yKCdudW1lcmljJyxuKSAjIGNvbnRhaW5lciBmb3IgY29tbXVuaXR5LXdpc2UgZGVncmVlCglmb3IgKGkgaW4gMTptYXgoQ2kpKSB7CgkJS2MyID0gS2MyK3Jvd1N1bXModyooR2M9PWkpKV4yICMgZ3JhYiBjb21tdW5pdHkgZGVncmVlCgl9CglQIDwtIHJvdW5kKGFycmF5KDEsbiktS2MyLyhLb14yKSw0KSAjIGNhbGN1bGF0ZSBhbmQgcm91bmQgcGFydGljaXBhdGlvbiBjb2VmZmljaWVudAoJcmV0dXJuKFApCn0KCiMgY2FsY3VsYXRlIHBhcnRpY2lwYXRpb24gY29lZmZpY2llbnRzCnBhcnQuY29lZnMgPC0gYXJyYXkoMCwgZGltID0gYygxMjgsIGxlbmd0aChpZHMkc3ViaikpKQpjb3VudCA8LSAwCmZvciAoc3MgaW4gbGV2ZWxzKGlkcyRzdWJqKSkgewoJY291bnQgPC0gY291bnQrMQoJcGFydC5jb2Vmc1ssY291bnRdIDwtIHBhcnQuY29lZihjb3JtYXRzW1tzc11dLCBjaSRjb20pCn0KcGFydC5jb2VmcyA8LSBhcGVybShwYXJ0LmNvZWZzKQpwYXJ0LmNvZWZzIDwtIGRhdGEuZnJhbWUocGFydC5jb2VmcywgU1VCX0lEPWlkcyRzdWJqKQoKIyBncmFiIHRoZSBmaW5hbCBzYW1wbGUgYW5kIG1lcmdlIGRhdGEKcm9pIDwtICdYMTA4Jwp0UCA8LSBkYXRhLmZyYW1lKFNVQl9JRD1wYXJ0LmNvZWZzJFNVQl9JRCxyb2k9cGFydC5jb2Vmc1sscm9pXSkKdFAgPC0gbWVyZ2UocGhlbm8sIHRQLCBieT0nU1VCX0lEJykKZmluIDwtIHN1YnNldCh0UCwgdFAkU0VYPT0xICYgdFAkTWVhbjwwLjEgJiB0UCRBR0VfQVRfU0NBTjwxOS43NCkKZmluIDwtIGZpbltjb21wbGV0ZS5jYXNlcyhmaW4kcm9pKSxdCmBgYAoKTm93IGV4YW1pbmUgdGhlIGludGVyYWN0aW9uIGVmZmVjdCBiZXR3ZWVuIGRpYWdub3N0aWMgZ3JvdXAgYW5kIGFnZSBvbiBwYXJ0aWNpcGF0aW9uIGNvZWZmaWNpZW50CgpgYGB7ciBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gOCwgZmlnLmFsaWduID0gJ2NlbnRlcid9CnN1bW1hcnkobG0ocm9pIH4gRFhfR1JPVVAqQUdFX0FUX1NDQU4gKyBNZWFuICsgRklRICsgRVlFX1NUQVRVU19BVF9TQ0FOLCBkYXRhPWZpbikpCgptb2QgPC0gbG0ocm9pIH4gTWVhbiArIEZJUSArIEVZRV9TVEFUVVNfQVRfU0NBTiwgZGF0YT1maW4pCm5ldyA8LSBkYXRhLmZyYW1lKHJlcz1yZXNpZHVhbHMobW9kKSxncnA9ZmluJERYX0dST1VQLGFnZT1maW4kQUdFX0FUX1NDQU4pCm5ldyRHcm91cCA8LSByZXZhbHVlKGFzLmZhY3RvcihuZXckZ3JwKSwgYygnMSc9J0FTRCcsICcyJz0nVEQnKSkKCmdncGxvdChuZXcsIGFlcyhhZ2UscmVzLGNvbG9yPUdyb3VwKSkgKyAKCWdlb21fcG9pbnQoKSArIAoJZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScsZmlsbD0nZ3JleTgwJykgKwoJc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCdmb3Jlc3RncmVlbicsJ3N0ZWVsYmx1ZScpKSArCglzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOSwyMCkpICsKCXNjYWxlX3lfY29udGludW91cyhicmVha3M9YygtLjEsMCkpICsKCXRoZW1lX2J3KCkgKwoJbGFicyh4PSdBZ2UnLHk9J1Jlc2lkdWFscycpICsKCXRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTE0KSwKCQlheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xNCkpCgpgYGAKLS0tLS0KCgojIyMgUHJlcGFyZSBDaXJjb3MgZGF0YSBmaWxlcwoKIyMjIyBUaGUga2FyeW90cHllIGZpbGUKCk1vcmUgaW5mbyBbaGVyZV0oaHR0cDovL2NpcmNvcy5jYS9kb2N1bWVudGF0aW9uL3R1dG9yaWFscy9pZGVvZ3JhbXMva2FyeW90eXBlcy8pCgpgYGAKY2hyIC0gSUQgTEFCRUwgU1RBUlQgRU5EIENPTE9SCmJhbmQgSUQgTEFCRUwgTEFCRUwgU1RBUlQgRU5EIENPTE9SCmBgYAoKLSBgY2hyYDogZGVmaW5pdGlvbiBvZiBhIGNocm9tb3NvbWUKLSBgYmFuZGA6IGJhbmQgd2l0aGluIGEgY2hyb21vc29tZQotIGBJRGA6IGlkZW50aWZlciwgd2hpY2ggY2FuIGJlIHVzZWQgaW4gcGxvdCBsYWJlbHMKLSBgc3RhcnRgIGFuZCBgZW5kYDogZGVub3RlcyB0aGUgc2l6ZSBvZiB0aGUgY2hyb21vc29tZSAoZWcgMCA5OSkKLSBgY29sb3JgCgotLS0tLQoKCiMjIyMgTWFudWFsbHkgY3JlYXRlZCBzdHJ1Y3R1cmUgZmlsZQoKYGBge3IgZW5naW5lID0gJ2Jhc2gnLCBjb21tZW50ID0gJyd9CmNhdCAuL3Jhdy90eHQvY2lyX3ByZXBfc3RyLmNzdgpgYGAKCiMjIyMgU3RydWN0dXJlIGxhYmVscwoKYGBge3J9CnN0ciA8LSByZWFkLmNzdignLi9yYXcvdHh0L2Npcl9wcmVwX3N0ci5jc3YnLHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCnN0ciRtb2R1bGUgPC0gZmFjdG9yKHN0ciRtb2R1bGUsbGV2ZWxzPWMoJ1N1YmNvcnRpY2FsJywnVmlzdWFsJywnU29tYXRvbW90b3InLCdMaW1iaWMnLCdDb250cm9sJywnVmVudEF0dG4nLCdEb3JzQXR0bicsJ0RlZmF1bHQnKSkKbiA8LSBsZW5ndGgoc3RyJG1vZHVsZSkKaGVtaSA8LSBhcy5mYWN0b3IoYygnbGgnLCdyaCcpKQoKY2hyIDwtIHZlY3RvcignY2hhcmFjdGVyJyxuKQppbml0IDwtIHZlY3RvcignbnVtZXJpYycsbikKZW5kIDwtIHZlY3RvcignbnVtZXJpYycsbikKbmFtZSA8LSB2ZWN0b3IoJ2NoYXJhY3RlcicsbikKaWkgPC0gMApmb3IgKG1tIGluIGxldmVscyhzdHIkbW9kdWxlKSkgewoJbC5sb2MgPC0gMAoJci5sb2MgPC0gMAoJZm9yIChoaCBpbiBsZXZlbHMoaGVtaSkpIHsKCQl0ZW1wIDwtIHN1YnNldChzdHIsc3RyJG1vZHVsZT09bW0gJiBzdHIkaGVtaT09aGgpCgkJZm9yIChyciBpbiAxOmxlbmd0aCh0ZW1wJHJvaSkpIHsKCQkJaWkgPC0gaWkrMQoJCQlpZiAodGVtcCRoZW1pW3JyXT09J2xoJykgewoJCQkJY2hyW2lpXSA8LSBwYXN0ZTAodGVtcCRtb2R1bGVbcnJdLCctbCcpCgkJCQlpbml0W2lpXSA8LSBsLmxvYwoJCQkJZW5kW2lpXSA8LSBsLmxvYys5OQoJCQkJbmFtZVtpaV0gPC0gdGVtcCRyb2lbcnJdCgkJCQlsLmxvYyA8LSBsLmxvYysxMDAKCgkJCX0gZWxzZSB7CgkJCQljaHJbaWldIDwtIHBhc3RlMCh0ZW1wJG1vZHVsZVtycl0sJy1yJykKCQkJCWluaXRbaWldIDwtIHIubG9jCgkJCQllbmRbaWldIDwtIHIubG9jKzk5CgkJCQluYW1lW2lpXSA8LSB0ZW1wJHJvaVtycl0KCQkJCXIubG9jIDwtIHIubG9jKzEwMAoJCQl9CgkJfQoJfQp9CnN0ci5sYWJlbCA8LSBkYXRhLmZyYW1lKGNocixpbml0LGVuZCxuYW1lKQp3cml0ZS50YWJsZShzdHIubGFiZWwsJy4vY2lyY29zX2RhdGEvZGF0YS9zdHJ1Y3R1cmUubGFiZWwudHh0Jyxjb2wubmFtZXM9RkFMU0Uscm93Lm5hbWVzPUZBTFNFLHF1b3RlPUZBTFNFKQpgYGAKCmBgYHtyIGVuZ2luZSA9ICdiYXNoJywgY29tbWVudCA9ICcnfQpjYXQgLi9jaXJjb3NfZGF0YS9kYXRhL3N0cnVjdHVyZS5sYWJlbC50eHQKYGBgCgotLS0tLQoKCiMjIyMgU2VnbWVudCBsYWJlbHMKCmBgYHtyfQpkYXQgPC0gc3RyLmxhYmVsCmNvbC4xIDwtIHZlY3RvcignY2hhcmFjdGVyJyxuKQpjb2wuMiA8LSB2ZWN0b3IoJ2NoYXJhY3RlcicsbikKY29sLjMgPC0gdmVjdG9yKCdjaGFyYWN0ZXInLG4pCmNvbC40IDwtIHZlY3RvcignY2hhcmFjdGVyJyxuKQpjb2wuNSA8LSB2ZWN0b3IoJ251bWVyaWMnLG4pCmNvbC42IDwtIHZlY3RvcignbnVtZXJpYycsbikKY29sLjcgPC0gdmVjdG9yKCdjaGFyYWN0ZXInLG4pCgppaSA8LSAwCmZvciAobW0gaW4gbGV2ZWxzKGRhdCRjaHIpKSB7CglpaSA8LSBpaSsxCgl0ZW1wIDwtIHN1YnNldChkYXQsIGRhdCRjaHI9PW1tKQoJY29sLjFbaWldIDwtICdjaHInCgljb2wuMltpaV0gPC0gJy0nCgljb2wuM1tpaV0gPC0gYXMuY2hhcmFjdGVyKHRlbXAkY2hyWzFdKQoJY29sLjRbaWldIDwtIHN0cnNwbGl0KGFzLmNoYXJhY3Rlcih0ZW1wJGNoclsxXSksJy0nKVtbMV1dWzFdCgljb2wuNVtpaV0gPC0gMAoJY29sLjZbaWldIDwtIG1heCh0ZW1wJGVuZCkKCWNvbC43W2lpXSA8LSAnYmxhY2snCglzdWIuc3RyIDwtIHN1YnNldChzdHIsIHN0ciRtb2R1bGUgPT0gc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKHRlbXAkY2hyWzFdKSwnLScpW1sxXV1bMV0pCglmb3IgKHJyIGluIDE6bGVuZ3RoKHRlbXAkbmFtZSkpIHsKCQlpaSA8LSBpaSsxCgkJY29sLjFbaWldIDwtICdiYW5kJwoJCWNvbC4yW2lpXSA8LSBhcy5jaGFyYWN0ZXIodGVtcCRjaHJbcnJdKQoJCWNvbC4zW2lpXSA8LSBhcy5jaGFyYWN0ZXIodGVtcCRuYW1lW3JyXSkKCQljb2wuNFtpaV0gPC0gYXMuY2hhcmFjdGVyKHRlbXAkbmFtZVtycl0pCgkJY29sLjVbaWldIDwtIHRlbXAkaW5pdFtycl0KCQljb2wuNltpaV0gPC0gdGVtcCRlbmRbcnJdCgkJY29sLjdbaWldIDwtIHN1Yi5zdHIkY29sLm5hbWVbZ3JlcCh0ZW1wJG5hbWVbcnJdLHN1Yi5zdHIkcm9pKVsxXV0gCgl9Cn0Kc2VnIDwtIGRhdGEuZnJhbWUoY29sLjEsY29sLjIsY29sLjMsY29sLjQsY29sLjUsY29sLjYsY29sLjcpCndyaXRlLnRhYmxlKHNlZywnLi9jaXJjb3NfZGF0YS9kYXRhL3NlZ21lbnRzLnR4dCcsY29sLm5hbWVzPUZBTFNFLHJvdy5uYW1lcz1GQUxTRSxxdW90ZT1GQUxTRSkKYGBgCgpgYGB7ciBlbmdpbmUgPSAnYmFzaCcsIGNvbW1lbnQgPSAnJ30KY2F0IC4vY2lyY29zX2RhdGEvZGF0YS9zZWdtZW50cy50eHQKYGBgCgotLS0tLQoKCiMjIyBMaW5rcwoKIyMjIyBEZWZpbmluZyBsaW5rcwoKTW9yZSBpbmZvIFtoZXJlXShodHRwOi8vY2lyY29zLmNhL2RvY3VtZW50YXRpb24vdHV0b3JpYWxzL2xpbmtzL2Jhc2ljX2xpbmtzLykKCmBgYApDSFJfU1RBUlQgU1RBUlQgRU5EIENIUl9FTkQgU1RBUlQgRU5EIHR5cGU9MSwgc2NvcmU9MQpgYGAKCmBDSFJfU1RBUlRgOiBDaHJvbW9zb21lIGxpbmsgYmVnaW5zCmBTVEFSVGAgYW5kIGBFTkRgOiBsb2NhdGlvbiBvbiBjaHJvbW9zb21lCmB0eXBlYDogY2FuIGJlIHVzZWQgZm9yIHJ1bGVzCmBzY29yZWA6IGNhbiBiZSB1c2VkIGZvciBydWxlcyAoSSB1c2UgaXQgZm9yIGxpbmsgd2VpZ2h0KQoKLS0tLS0KCgpGb3IgdGhlIHBvc3RlciBJIHdhbnRlZCA0IGNvbm5lY3RvZ3JhbXMgdG8gc2hvdyB0aGUgZ3JvdXAgYnkgYWdlIGludGVyYWN0aW9uOgoKLSB5b3VuZ2VyIGhhbGYgb2Ygc2FtcGxlCgkrIFREID4gQVNECgkrIEFTRCA+IFRECi0gb2xkZXIgaGFsZiBvZiBzYW1wbGUKCSsgVEQgPiBBU0QKCSsgQVNEID4gVEQKCkZvciB0aGlzIGV4YW1wbGUgSSdsbCBqdXN0IHNob3cgVEQgPiBBU0QgaW4gdGhlIG9sZGVyIHNhbXBsZS4KCmBgYHtyfQojIENyZWF0ZSBncm91cC1hdmVyYWdlZCBtYXRyaWNlcwpncnAubWF0IDwtIGZ1bmN0aW9uKHN1YnMsbWF0cyxuKSB7CglmaW4ubWF0IDwtIGFycmF5KDAsIGRpbT1jKG4sbikpCglmb3IgKHNzIGluIDE6bGVuZ3RoKHN1YnMpKSB7CgkJZmluLm1hdCA8LSBmaW4ubWF0K2Nvcm1hdHNbW3N1YnNbc3NdXV0KCX0KCWZpbi5tYXQgPC0gZmluLm1hdC9sZW5ndGgoc3VicykKCXJldHVybihmaW4ubWF0KQp9CnByZXAuY2lyY29zLmxpbmtzIDwtIGZ1bmN0aW9uKG1hdCxndWlkZSkgewoJdGVtcCA8LSBtYXQqbG93ZXIudHJpKG1hdCkKCXRlbXAgPC0gcm91bmQodGVtcCwzKQoJTiA8LSBuY29sKG1hdCkKCW4gPC0gbGVuZ3RoKHRlbXBbdGVtcD4wXSkKCXMubmFtZSA8LSB2ZWN0b3IoJ2NoYXJhY3RlcicsbikKCXMub24gPC0gdmVjdG9yKCdudW1lcmljJyxuKQoJcy5vZmYgPC0gdmVjdG9yKCdudW1lcmljJyxuKQoJZS5uYW1lIDwtIHZlY3RvcignbnVtZXJpYycsbikKCWUub24gPC0gdmVjdG9yKCdudW1lcmljJyxuKQoJZS5vZmYgPC0gdmVjdG9yKCdudW1lcmljJyxuKQoJdHlwZSA8LSB2ZWN0b3IoJ2NoYXJhY3RlcicsbikKCWluZCA8LSAxCglmb3IgKGlpIGluIDE6TikgewoJCWZvciAoamogaW4gMTpOKSB7CgkJCWlmICh0ZW1wW2lpLGpqXT4wKSB7CgkJCQlzLm5hbWVbaW5kXSA8LSBhcy5jaGFyYWN0ZXIoZ3VpZGUkbmFtZVtpaV0pCgkJCQlzLm9uW2luZF0gPC0gZ3VpZGUkb25baWldCgkJCQlzLm9mZltpbmRdIDwtIGd1aWRlJG9mZltpaV0KCQkJCWUubmFtZVtpbmRdIDwtIGFzLmNoYXJhY3RlcihndWlkZSRuYW1lW2pqXSkKCQkJCWUub25baW5kXSA8LSBndWlkZSRvbltqal0KCQkJCWUub2ZmW2luZF0gPC0gZ3VpZGUkb2ZmW2pqXQoJCQkJdHlwZVtpbmRdIDwtIHBhc3RlMCgndHlwZT0xLHNjb3JlPScsdGVtcFtpaSxqal0pCgkJCQlpbmQgPC0gaW5kKzEKCQkJfQoJCX0KCX0KCWZpbiA8LSBkYXRhLmZyYW1lKHMubmFtZSxzLm9uLHMub2ZmLGUubmFtZSxlLm9uLGUub2ZmLHR5cGUpCglyZXR1cm4oZmluKQp9CgptIDwtIG1lYW4oZmluJEFHRV9BVF9TQ0FOKQpvbGQgPC0gc3Vic2V0KGZpbiwgZmluJEFHRV9BVF9TQ0FOPm0pCmEubyA8LSBzdWJzZXQob2xkLCBvbGQkRFhfR1JPVVA9PTEpICMgQVNEIGdyb3VwCmEubWF0IDwtIGdycC5tYXQoYS5vJFNVQl9JRCxjb3JtYXRzLDEyOCkKYS5tYXRbLTEwOCwtMTA4XSA8LSAwICMgemVybyBvdXQgYWxsIGJ1dCBST0kKCnQubyA8LSBzdWJzZXQob2xkLCBvbGQkRFhfR1JPVVA9PTIpICMgVEQgZ3JvdXAKdC5tYXQgPC0gZ3JwLm1hdCh0Lm8kU1VCX0lELGNvcm1hdHMsMTI4KQp0Lm1hdFstMTA4LC0xMDhdIDwtIDAgIyB6ZXJvIG91dCBhbGwgYnV0IFJPSQoKdC5taW51cy5hIDwtIHQubWF0LWEubWF0CgpndWlkZSA8LSBzdHIubGFiZWwKbmFtZXMoZ3VpZGUpIDwtIGMoJ25hbWUnLCdvbicsJ29mZicpCiAKbGlua3MgPC0gcHJlcC5jaXJjb3MubGlua3ModC5taW51cy5hLGd1aWRlKQp3cml0ZS50YWJsZShsaW5rcywnLi9jaXJjb3NfZGF0YS9kYXRhL2xpbmtzLnR4dCcsY29sLm5hbWVzPUZBTFNFLHJvdy5uYW1lcz1GQUxTRSxxdW90ZT1GQUxTRSkKYGBgCgpgYGB7ciBlbmdpbmUgPSAnYmFzaCcsIGNvbW1lbnQgPSAnJ30KY2F0IC4vY2lyY29zX2RhdGEvZGF0YS9saW5rcy50eHQKYGBgCgoKLS0tLS0KCgojIyBDaXJjb3MgY29uZmlnIGZpbGUKCmBgYHtyIGVuZ2luZSA9ICdiYXNoJywgY29tbWVudCA9ICcnfQpjYXQgLi9jaXJjb3NfZGF0YS9ldGMvY2lyY29zLmNvbmYKYGBgCgojIyMgU2FtcGxlIGltcG9ydGVkIGNvbmZpZyBmaWxlCgpgYGB7ciBlbmdpbmUgPSAnYmFzaCcsIGNvbW1lbnQgPSAnJ30KY2F0IC4vY2lyY29zX2RhdGEvZXRjL2lkZW9ncmFtLmNvbmYKYGBgCgotLS0tLQoKIyMjIFJ1biBDaXJjb3MKCmBgYHtyIGVuZ2luZSA9ICdiYXNoJywgY29tbWVudCA9ICcnfQpjZCAuL2NpcmNvc19kYXRhCmNpcmNvcwpgYGAKCi0tLQoKIyMjIEZpbmFsIHBsb3QKCkNpcmNvcyBkb2VzIG5vdCBnZW5lcmF0ZSBsZWdlbmRzIG9yIGV4dHJhIGxhYmVscyAoc3VjaCBhcyB0aGUgaGVtaXNwaGVyZSBkZXNpZ25hdGlvbiBpbiBteSBmaWd1cmUpLgpUaGVzZSBuZWVkIHRvIGJlIG1hbnVhbGx5IGFkZGVkIGluIHlvdXIgZmlndXJlIGVkaXRvciAoZS5nLiwgSWxsdXN0cmF0aW9uLCBQb3dlciBQb2ludCkKCjxjZW50ZXI+CgkhW10oLi9pbWcvZmluYWxfcGxvdC5wbmcpe3dpZHRoPTEwMCV9CjwvY2VudGVyPgoKCg==